//
//  UWGameView.m
//  Urban Words
//
//  Created by Tim Brandin on 2011-11-30.
//  Copyright (c) 2011 Sypreme. All rights reserved.
//

#import <AudioToolbox/AudioToolbox.h>

#import "UWAppDelegate.h"
#import "UWGameView.h"
#import "UILabel+UW.h"
#import "UWFriend.h"
#import "UWFriendManager.h"
#import "BoardPrefs.h"
#import "UWTile.h"
#import "UWWord.h"
#import "UWApi.h"
#import "NSMutableArray+Randomization.h"
#import "NSMutableURLRequest+BasicAuth.h"
#import "UWFriendManager.h"

@interface UWGameView()
// private methods
- (void)clearSound;
- (void)clearSoundSingle;
- (NSDictionary *)getPlayedTiles;
- (NSString *)getBoard;
- (NSString *)getNewBoard;
- (BOOL)findConnection:(int)brick onBoard:(NSString *)board;
- (BOOL)checkTiles:(NSString *)board;
- (NSArray *)findWords:(NSString *)board;
- (BOOL)checkWords:(NSArray *)words;
- (void)removeTiles;
- (void)popTilesBackUp;
- (int)countPlayedTiles:(NSString *)board;
@end

@implementation UWGameView

@synthesize dataSource;

@synthesize game;
@synthesize board_view;
@synthesize timer;
@synthesize panel;
@synthesize tiles;
@synthesize pusher = _pusher;
@synthesize currentChannel;
@synthesize scoreBoard;


@synthesize gameBoard;
@synthesize historyTableContainer;
@synthesize curtain;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        tiles = [[NSMutableArray array] retain];
        isLoadedOnce = NO;
        
        self.pusher = ((UWAppDelegate *)[[UIApplication sharedApplication] delegate]).pusher;
        
        // Pusher: channel init
        connectedClients = [[NSMutableArray alloc] init];
        memberIDs = [[NSMutableArray alloc] init];
        
        // Pusher: configure the auth URL for private/presence channels
        NSString *fid = [[NSUserDefaults standardUserDefaults] valueForKey:@"Fid"];
        self.pusher.authorizationURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://sypreme.se/uw/src/presence_auth.php?user_id=%@", fid]];
        
        // Bind to move event
        [self.pusher bindToEventNamed:@"move" target:self action:@selector(handleMoveEvent:)];
        
        
        // no rows or columns are visible at first; note this by making the firsts very high and the lasts very low
        firstVisibleRow = firstVisibleColumn = NSIntegerMax;
        lastVisibleRow = lastVisibleColumn = NSIntegerMin;
        
        // navigation bar buttons
        sendButton = [[UIBarButtonItem alloc] initWithTitle:@"Play" 
                                        style:UIBarButtonItemStyleDone 
                                        target:self 
                                        action:@selector(play)];
        
        [sendButton setTintColor:[UIColor colorWithRed:0 green:0 blue:0.8 alpha:1.0]];
        
        clearButton = [[UIBarButtonItem alloc] initWithTitle:@"Clear" 
                                                                 style:UIBarButtonItemStyleDone 
                                                                target:self 
                                                                action:@selector(clear)];
        
        [self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:sendButton, clearButton, nil] animated:YES];
        
    }
    return self;
}

#pragma mark - Urban Words methods

- (void)play
{
    NSString *board = [self getBoard];
    if ([self checkTiles:board]) {
        
        NSMutableDictionary *playedTiles = [NSMutableDictionary dictionary];
        [playedTiles setValue:[self getPlayedTiles] forKey:@"chars"];
        
        //[sendButton setEnabled:NO];
        
        [UWApi update:[NSString stringWithFormat:@"play/%i", game.gameid] 
             withData:playedTiles listener:self action:@selector(playLoaded:)];
    }
    else {
        
        // mark played bricks with fail
        
        // hide played tiles
        // after 2000 ms 
        //      show them again
        //      mark failed BRICKS with NONE
        //      remove the letters added in gameBoard
        //      update gameBoard view, setNeedsDisplay
        
        NSLog(@"tiles failed!");
    }
    
    // show animations
   // [self repaintWithAnimation];
}

- (void)playLoaded:(NSData *)data
{
    NSDictionary *response = (NSDictionary *)[UWApi parseJson:data];
    
    if ([(NSString *)[response valueForKey:@"play"] isEqualToString:@"ok"]) {
        NSLog(@"play ok");
        
        for (UWTile *t in tiles) {
            if (t.brick != -1) {
                [UIView beginAnimations:nil context:NULL];
                [UIView setAnimationDuration:0.1];
                
                t.remove = YES;
                
                t.brick = -1;
                t.alpha = 0;
                
                [UIView commitAnimations];
            }
        }
        
        [self performSelector:@selector(removeTiles) withObject:nil afterDelay:1];
        
    } else {
        NSLog(@"play fail");
        
        if ([[response objectForKey:@"message"] isKindOfClass:[NSString class]]) {
            
            NSLog(@"fail: %@", [response objectForKey:@"message"]);
        } else {
        
            NSArray *failedWords = (NSArray *)[response objectForKey:@"message"];
            
            
            [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:0.1];
            
            for (UWTile *t in tiles) {
                if (t.brick != -1) {
                    
                    t.alpha = 0;
                    
                    [gameBoard setLetter:t.letter.text atPos:t.brick withState:FAIL];
                }
            }
            
            [UIView commitAnimations];
            
            AudioServicesPlaySystemSound(gameBoard.fail);
            
            for (NSObject *word in failedWords) {
                NSString *str = [word valueForKey:@"word"];
                int id = [((NSNumber *)[word valueForKey:@"id"]) intValue];
                int h = [((NSNumber *)[word valueForKey:@"h"]) intValue];
                
                NSLog(@"%@ %@ %@", [word valueForKey:@"id"], 
                      [word valueForKey:@"word"], [word valueForKey:@"h"]);
                
                [gameBoard putWord:str atPos:id atDirection:h withState:FAIL];
            }
            
            [self repaintWithAnimation];
            
            [self performSelector:@selector(popTilesBackUp) withObject:nil afterDelay:2];
            
            NSLog(@"play: %@", [response valueForKey:@"play"]);
        }
    }
    
}

- (void)removeTiles
{
    NSMutableArray *keep = [NSMutableArray array];
    
    for (UWTile *t in tiles) {
        if (!t.remove) {
            [keep addObject:t];
        }
    }
    
    [tiles release];
    tiles = [keep retain];
}

- (void)popTilesBackUp
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.1];
    
    for (UWTile *t in tiles) {
        if (t.alpha == 0 && t.brick != -1) {
            t.alpha = 1;
            [gameBoard clearLetterAtPos:t.brick];
        }
    }
    
    [UIView commitAnimations];
    
    [gameBoard setNeedsDisplay];
}

- (NSDictionary *)getPlayedTiles
{
    NSMutableDictionary *playedTiles = [NSMutableDictionary dictionary];
    
    for (UWTile *t in tiles) {
        if (t.brick != -1) {
            [playedTiles setValue:t.letter.text forKey:[NSString stringWithFormat:@"%i", t.brick]];
            NSLog(@"char:%@ , loc: %i", t.letter.text, t.brick);
        }
    }
    
    return playedTiles;
}

- (NSString *)getBoard
{
    NSMutableString *temporaryBoard = [NSMutableString stringWithCapacity:225];
    
    for(int i = 0; i < 255; i++) {
        [temporaryBoard appendString:@" "];
    }
    
    // decompress board
    int j = 0;
    for(int i=0; i < [game.board length]; i++) {
        unichar c = [game.board characterAtIndex:i];
        int ci = c;
        if (ci > 97) {
            j += ci-97;
        }
        else{
            [temporaryBoard replaceCharactersInRange:NSMakeRange(j, 1) withString:[NSString stringWithFormat:@"%C", c]];
            j++;
        }
    }
    
    return [NSString stringWithString:temporaryBoard];
}

- (NSString *)getNewBoard
{
    NSMutableString *temporaryBoard = [NSMutableString stringWithString:[self getBoard]];
    
    // add tiles to temporary Board
    for (UWTile *t in tiles) {
        if (t.brick != -1) {
            
            if (temporaryBoard.length > t.brick) {
                [temporaryBoard replaceCharactersInRange:NSMakeRange(t.brick, 1) withString:t.letter.text];
            }

        }
    }
    
    return [NSString stringWithString:temporaryBoard];
}

- (int)countPlayedTiles:(NSString *)board
{
    int j=0;
    for (int i =0; i < board.length; i++) {
        if ([board characterAtIndex:i] != ' ')
            j++;
    }
    return j;
}

// findConnection: version 1.5
- (BOOL)findConnection:(int)brick onBoard:(NSString *)board
{
    // check star brick
    if ([self countPlayedTiles:board] == 0
        && brick == (BRICK_COUNT * BRICK_COUNT - 1) / 2) {
        return YES;
    }
    
    // check left connection
    if (brick - BRICK_COUNT >= 0
        && (brick - BRICK_COUNT) > (int)((brick - BRICK_COUNT)/BRICK_COUNT) * BRICK_COUNT
        && [board characterAtIndex:(brick - BRICK_COUNT)] != ' ') {
        
        return YES;
    }
    
    // find upper connection
    if (brick - 1 >= 0
        && (brick - 1) > (int)((brick - 1)/BRICK_COUNT) * BRICK_COUNT 
        && [board characterAtIndex:(brick - 1)] != ' ') {
        
        return YES;
    }
    
    // check right connection
    if (brick + BRICK_COUNT < BRICK_COUNT * BRICK_COUNT
        && (brick + BRICK_COUNT) < (int)((brick + BRICK_COUNT)/BRICK_COUNT + 1) * BRICK_COUNT
        && [board characterAtIndex:(brick + BRICK_COUNT)] != ' ') {
        
        return YES;
    }
    
    // find lower connection
    if (brick + 1 < BRICK_COUNT * BRICK_COUNT
        && (brick + 1) < (int)((brick + 1)/BRICK_COUNT + 1) * BRICK_COUNT
        && [board characterAtIndex:(brick + 1)] != ' ') { // no more letters
        
        return YES;
    }
    
    return NO;
}

// checkTiles: version 2.0 (objective-c)
- (BOOL)checkTiles:(NSString *)board
{
    
    BOOL isConnected = NO;
    BOOL tileConnection = YES;
    
    // sort tiles by position
    NSSortDescriptor *sortdescriptor = [[[NSSortDescriptor alloc] 
                                         initWithKey:@"brick" ascending:YES] autorelease];
    [tiles sortUsingDescriptors:[NSArray arrayWithObject:sortdescriptor]];
    
    int first = -1;
    int previous = -1;
    UWDirection direction = NOTSET;
    
    // go right and down for each tile, until another tile is found or the board-edge
    for (UWTile *t in tiles) {
        if (t.brick != -1) {
            
            if (first < 0) { // first tile
                first = t.brick;
            }
            else {
                int width = (t.brick - first) / BRICK_COUNT;
                int height = abs(t.brick % BRICK_COUNT - first % BRICK_COUNT);
                BOOL wh = (width == 0) == (height == 0);
                BOOL dir = (width > 0 && height == 0);
                
                if (direction == NOTSET) { // other tiles
                    direction = dir;

                    if (wh) {
                        direction = FAILED;
                        break;
                    }
                    
                }
                else {
 
                    if (wh || dir != direction) { // direction changed
                        direction = FAILED;
                        break; // exit loop
                    }
                }
                
                // check connection between tiles
                for (int i = 1; i < BRICK_COUNT; i++) {
                    
                    if (tileConnection) {
                        
                        // find connection to left tile
                        if (direction) { // horizontal
                            
                            // find left connection
                            if (t.brick - i * BRICK_COUNT < 0
                                || (t.brick - i * BRICK_COUNT) <= (int)((t.brick - i * BRICK_COUNT)/BRICK_COUNT) * BRICK_COUNT
                                || [board characterAtIndex:(t.brick - i * BRICK_COUNT)] == ' ') {
                                
                                if (previous != t.brick - i * BRICK_COUNT)
                                    tileConnection = NO;
                                    
                                break;
                            } 
                            
                        }
                        
                        // find connection to upper tile
                        else { // vertical
                            
                            // find upper connection
                            if (t.brick - i < 0 
                                || (t.brick - i) <= (int)((t.brick - i)/BRICK_COUNT) * BRICK_COUNT
                                || [board characterAtIndex:(t.brick - i)] == ' ') {
                                
                                if (previous != t.brick - i)
                                    tileConnection = NO;
                                
                                break;
                            }
                            
                        }
                    } 
                    else {
                        break; // exit loop
                    }
                    
                }
                
                if (direction == FAILED || !tileConnection) {
                    break; // exit loop
                }
            }
            
            if (!isConnected)
                isConnected = [self findConnection:t.brick onBoard:board];
            
            previous = t.brick;
        }
    }
    
    return isConnected && direction != FAILED && tileConnection;
}

- (NSArray *)findWords:(NSString *)board
{
    
    // list of words
    NSMutableDictionary *horizontalWords = [NSMutableDictionary dictionaryWithCapacity:10];
    NSMutableDictionary *verticalWords = [NSMutableDictionary dictionaryWithCapacity:10];
    int cols[BRICK_COUNT];
    int rows[BRICK_COUNT];
    
    // find words
    for (UWTile *t in tiles) {
        if (t.brick != -1) {
            int minX, maxX, minY, maxY;
            BOOL x1, x2, y1, y2;
            x1 = x2 = y1 = y2 = NO; 
            minX = maxX = minY = maxY = t.brick;
            
            NSMutableString *horizontal = [NSMutableString stringWithString:[board substringWithRange:NSMakeRange((t.brick), 1)]];
            NSMutableString *vertical = [NSMutableString stringWithString:[board substringWithRange:NSMakeRange((t.brick), 1)]];
            
            // find limits
            for (int i = 1; i < BRICK_COUNT; i++) {
                // minY
                if (!y1 && (t.brick - i) > (int)((t.brick-i)/BRICK_COUNT) * BRICK_COUNT 
                    && t.brick - i >= 0
                    && [board characterAtIndex:(t.brick - i)] != ' ') {
                    
                    minY--;
                    
                    [vertical insertString:[board substringWithRange:NSMakeRange((t.brick - i), 1)] atIndex:0];
                    
                } else {
                    y1 = YES;
                }
                
                // maxY
                if (!y2 && (t.brick + i) < (int)(((t.brick+i)/BRICK_COUNT)+1) * BRICK_COUNT 
                    && t.brick + i < 225
                    && [board characterAtIndex:(t.brick + i)] != ' ') {
                    
                    maxY++;
                    
                    [vertical appendString:[board substringWithRange:NSMakeRange((t.brick + i), 1)]];
                    
                } else {
                    y2 = YES;
                }
                
                // minX
                if (!x1 && (t.brick - i * BRICK_COUNT) > (int)((t.brick-i*BRICK_COUNT)/BRICK_COUNT) * BRICK_COUNT
                    && t.brick - i * BRICK_COUNT >= 0
                    && [board characterAtIndex:(t.brick - i * BRICK_COUNT)] != ' ') {
                    
                    minX -= BRICK_COUNT;
                    
                    [horizontal insertString:[board substringWithRange:NSMakeRange((t.brick - i*BRICK_COUNT), 1)] atIndex:0];

                } else {
                    x1 = YES;
                }
                
                // maxX
                if (!x2 && (t.brick + i * BRICK_COUNT) < (int)(((t.brick+i*BRICK_COUNT)/BRICK_COUNT)+1) * BRICK_COUNT 
                    && t.brick + i * BRICK_COUNT < 225
                    && [board characterAtIndex:(t.brick + i * BRICK_COUNT)] != ' ') {
                    
                    maxX += BRICK_COUNT;
                    
                    [horizontal appendString:[board substringWithRange:NSMakeRange((t.brick + i*BRICK_COUNT), 1)]];

                } else {
                    x2 = YES;
                }
                
                if (y1 && y2 && x1 && x2) { // all limits found
                    break; // exit loop
                }
                
            }
            
            BOOL failX = NO, failY = NO;
            int col = (int)minX/BRICK_COUNT;
            int row = minY - ((int)minY/BRICK_COUNT)*BRICK_COUNT;
            
            if (horizontal.length > 1) {
                
                if (![horizontalWords valueForKey:[[NSNumber numberWithInt:minX] stringValue]]) {
                    if (cols[col] != minX) {
                        [horizontalWords setValue:
                            [[UWWord alloc] initWithWord:horizontal Position:minX Direction:HORIZONTAL] 
                                           forKey:[[NSNumber numberWithInt:minX] stringValue]];
                        cols[col] = minX;
                    } else {
                        failX = YES;
                    }
                } else {
                    failX = YES;
                }
            } else  {
                failX = YES;
            }
            if (vertical.length > 1) {
                if (![verticalWords valueForKey:[[NSNumber numberWithInt:minX] stringValue]]) {
                    if (rows[row] != minY) {
                        [verticalWords setValue:
                            [[UWWord alloc] initWithWord:vertical Position:minY Direction:VERTICAL]
                                         forKey:[[NSNumber numberWithInt:minY] stringValue]];
                        rows[row] = minY;
                    }
                } else {
                    failY = YES;
                }
                        
            } else {
                failY = YES;
            }
            
            // tile failed to add any word => fail play
            if (failX && failY) {
                t.brick_state = FAIL;
            }
        }
    }

    NSMutableArray *allWords = [NSMutableArray arrayWithArray:[horizontalWords allValues]];
    [allWords addObjectsFromArray:[verticalWords allValues]];
    
    return [NSArray arrayWithArray:allWords];
}

- (BOOL)checkWords:(NSDictionary *)words
{
    return YES;
}

- (void)pass
{
    
}

- (void)clear
{
    
    // sort tiles by position
    NSSortDescriptor *sortdescriptor = [[[NSSortDescriptor alloc] 
                                         initWithKey:@"panelPos" ascending:YES] autorelease];
    [tiles sortUsingDescriptors:[NSArray arrayWithObject:sortdescriptor]];
    
    for (UWTile *t in tiles) {
        if (t.brick != -1) {
            CGPoint boardPos = t.center;
            CGPoint panelBoardPos = [gameBoard convertPoint:boardPos toView:panel];
            t.center = panelBoardPos;
        }
    } 
    
    int i = 0;
    
    for (UWTile *t in tiles) {
        
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.1 + 0.05*i];
        
        [t highlight];
        [panel addSubview:t];
        if (t.brick != -1) {
            i++;
            
            // change state on old brick
            UWBrick *oldBrick = [gameBoard getBrickAt:t.brick];
            oldBrick.state = NONE;
            
            t.brick = -1;
            t.center = CGPointMake(t.panelPos * 318/7 + 2 + TILE_SIZE/2, panel.bounds.size.height/2 + 3);
            
            //[self performSelector:@selector(clearSound) withObject:nil afterDelay:(0.25+0.03*i++)];
            
        }
        
        [UIView commitAnimations];
    }  
    
    if (i>1) 
        [self performSelector:@selector(clearSound) withObject:nil afterDelay:0.05];
    else if (i!=0)
        [self performSelector:@selector(clearSoundSingle) withObject:nil afterDelay:0.05];
}

- (void)clearSound
{
    AudioServicesPlaySystemSound(gameBoard.shuffle);
}

- (void)clearSoundSingle
{
    AudioServicesPlaySystemSound(gameBoard.place);
}

- (void)swap
{
    
}

- (void)shuffle
{
    isShuffeling = YES;
    [tiles randomize];
    int i = 0;
    
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    
    for (UWTile *t in tiles) {
        t.panelPos = i++;
        if (t.brick == -1) {
            t.center = CGPointMake(t.panelPos * 318/7 + 2 + TILE_SIZE/2, panel.bounds.size.height/2 + 3);
        }
    }  
    
    [UIView commitAnimations];
    
    [self performSelector:@selector(endShuffle) withObject:nil afterDelay:0.1];
}

- (void)endShuffle
{
    AudioServicesPlaySystemSound(gameBoard.shuffle);
    isShuffeling = NO;
}

#pragma mark - Custom Pusher events

- (void)handleMoveEvent:(PTPusherEvent *)event
{
    CGRect rect  = [gameBoard putWords:event.data];
    
    float scale  = [board_view zoomScale];
    float height = board_view.bounds.size.height / scale;
    float width  = board_view.bounds.size.width / scale;
    
    CGPoint center = CGPointMake(rect.origin.x + rect.size.width/2, rect.origin.y + rect.size.height/2);
    
    float wScale = board_view.bounds.size.width / MAX(width, rect.size.width + BOARD_MARGIN);
    float hScale = board_view.bounds.size.height / MAX(height, rect.size.height + BOARD_MARGIN);
    
    float newScale = MIN(wScale, hScale);
    
    CGRect zoomRect = [self zoomRectForScale:newScale withCenter:center];
    [board_view zoomToRect:zoomRect animated:YES];
    
    [self repaintWithAnimation];
    
    NSString *trigger = [event.data valueForKey:@"trigger"];
    
    
    if ([trigger isEqualToString:[[NSUserDefaults standardUserDefaults] valueForKey:@"Fid"]]) {
        
        //[sendButton setEnabled:NO];
        
        AudioServicesPlaySystemSound(gameBoard.place);
    } else {
        
        [sendButton setEnabled:YES];
        
        AudioServicesPlaySystemSound(gameBoard.turn);
    }

    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}


#pragma mark - TapDetection on view inside UIScrollView

- (void)boardView:(UWGameBoard *)board gotSingleTapAtPoint:(CGPoint)tapPoint
{
    // hide navbar is one tap is triggered
    //[self.navigationController setNavigationBarHidden:![self.navigationController isNavigationBarHidden] animated:YES];
    //[self repaintWithAnimation];
}

- (void)boardView:(UWGameBoard *)board gotDoubleTapAtPoint:(CGPoint)tapPoint
{
    float newScale = [board_view zoomScale] == 1.0 ? 
                        [board_view zoomScale] / ZOOM_STEP // if scale = 1, zoom out
                        : [board_view zoomScale] * ZOOM_STEP; // otherwise, zoom in
    CGRect zoomRect = [self zoomRectForScale:newScale withCenter:tapPoint];
    [board_view zoomToRect:zoomRect animated:YES];
}

- (void)boardView:(UWGameBoard *)board gotTwoFingerTapAtPoint:(CGPoint)tapPoint
{
    float newScale = [board_view zoomScale] / ZOOM_STEP;
    CGRect zoomRect = [self zoomRectForScale:newScale withCenter:tapPoint];
    [board_view zoomToRect:zoomRect animated:YES];
}

- (UIView *)boardView:(UWGameBoard *)board hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGPoint lp = [self.view convertPoint:point toView:panel];
    
    NSSortDescriptor *sortdescriptor = [[[NSSortDescriptor alloc] 
                                         initWithKey:@"distance" ascending:YES] autorelease];
    
    float scale = (((gameBoard.frame.size.width-BOARD_MARGIN*2 +BRICK_MARGIN)/BRICK_COUNT)-BRICK_MARGIN) / BRICK_SIZE;

    CGPoint bp = [self.view convertPoint:point toView:board_view];
    
    if ([scoreBoard isOpen]) {
        if (bp.y * scale > 230)
            return scoreBoard.view;
        return friendViewController.view;
    }
    
    for (UWTile *t in tiles) {
        CGPoint tp = [panel convertPoint:lp toView:t];
        tp.y += TILE_SIZE; // adjust the position to match the flipped coord system
        
        t.distance = sqrtf(powf(t.center.x - point.x, 2) + powf(t.center.y - point.y, 2)) * scale;
        
    }
    
    [tiles sortUsingDescriptors:[NSArray arrayWithObject:sortdescriptor]];
    
    for (UWTile *t in tiles) {
        if (t.distance < 35 && t.brick > -1)
            return t;

    }
    
    return nil;
}
#pragma mark ReloadData

- (void)reloadData
{
    // reload done here
}

- (void)reloadDataWithNewContentSize:(CGSize)size
{
    // reload done here
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return gameBoard;
}
                       
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center
{
    CGRect zoomRect;
    
    zoomRect.size.height = [board_view frame].size.height / scale;
    zoomRect.size.width = [board_view frame].size.width / scale;
    
    zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
    zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
    
    return zoomRect;
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    UWFriend *opponent = [[UWFriendManager sharedManager] getFriend:game.opponent];
    
    
    // setup "nice" title
    UIView *labelContainer = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 120, 30)];
    labelContainer.backgroundColor = [UIColor clearColor];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(4, 0, 110, 30)];
    [label setSpecialText:opponent.first_name];
    [labelContainer addSubview:label];
    
    labelContainer.clipsToBounds = NO;
    
    // setup online indicator
    online_indicator = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 26, 26)];
    online_indicator.center = CGPointMake(-4, 15);
    online_indicator.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"offline"]];
    
    [labelContainer addSubview:online_indicator];
    self.navigationItem.titleView = labelContainer;
    [label release];
    
    if ((game.whosturn == 1  && [game.p1 isEqualToString:game.opponent])
        || (game.whosturn == 2  && [game.p2 isEqualToString:game.opponent])) {
       // [sendButton setEnabled:NO];
    }
        
    
    // setup default background color for board
    [board_view setBackgroundColor:[UIColor colorWithRed:0.827451 green:0.827451 blue:0.827451 alpha:1.0]];
    
    // create the game board
    gameBoard = [[UWGameBoard alloc] initWithFrame:CGRectMake(0, 0, BOARD_SIZE, BOARD_SIZE)];
    [gameBoard setBackgroundColor:[UIColor clearColor]];
    
    // assign the game datastructure to its inner board
    [gameBoard setGame:game];
    
    // add the game board to the scrollview
    [board_view addSubview:gameBoard];
    
    // enable tap event delegation
    [gameBoard setDelegate:self];
    
    
    // enable scrolling
    [board_view setScrollEnabled:YES];
    board_view.contentSize = gameBoard.frame.size;
    
    // enable zooming
    [board_view setMaximumZoomScale:1.0];
    [board_view setMinimumZoomScale:BOARD_MIN_SCALE];
    [board_view setClipsToBounds:YES];
    [board_view setDelegate:self];
    
    // panel setup
    [panel setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"tbbg"]]];
    [self buildPanel];
    
    // history setup
    scoreBoard = [[UWScoreBoard alloc] initWithNibName:@"UWScoreBoard" bundle:nil];
    [curtain addSubview:scoreBoard.view];
    
    [curtain addTouchListener:scoreBoard actionBegan:@selector(curtainTouchBegan:) actionEnded:@selector(curtainTouchEnded:) actionCancelled:@selector(curtainTouchCancelled:) actionMoved:@selector(curtainTouchMoved:)];
    
    scoreBoard.historyView = historyTableContainer;
    scoreBoard.opponentName.text = opponent.first_name;
    scoreBoard.opponentScore.text = [NSString stringWithFormat:@"%ip", ([game.opponent isEqualToString:game.p1] ? game.p1score : game.p2score)];
    scoreBoard.score.text = [NSString stringWithFormat:@"%ip", ([game.opponent isEqualToString:game.p1] ? game.p2score : game.p1score)];
    /*
    // load friends history
    friendViewController = [[UWHistoryController alloc] initWithNibName:@"UWHistoryController" bundle:nil];
    [historyTableContainer addSubview:friendViewController.tableView];
    
    [historyTableContainer setClipsToBounds:YES];
//    [friendViewController release];
    
    friendViewController.view.frame = CGRectMake(0, 0, 320, 346);
*/    
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    
    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload
{
    [self setBoard_view:nil];
    [self setGameBoard:nil];
    [self setPanel:nil];
    [historyTableContainer release];
    historyTableContainer = nil;
    [self setHistoryTableContainer:nil];
    [self setCurtain:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    // Pusher: subscribe in background to channel
    [self performSelectorInBackground:@selector(subscribeToPresenceChannel) withObject:nil];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    isShuffeling = NO;
    UIAccelerometer *accellerator = [UIAccelerometer sharedAccelerometer];
    accellerator.updateInterval = 1 / 50.0;
    
    if (!isLoadedOnce) {
        [board_view setZoomScale:BOARD_MIN_SCALE];
        isLoadedOnce = YES;
    }
    
    accellerator.delegate = self;
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    // Pusher
    if ([self.currentChannel isSubscribed]) {
        // unsubscribe before we go back to the main menu
        [self.pusher unsubscribeFromChannel:self.currentChannel];
    }
    
    
    UIAccelerometer *accellerator = [UIAccelerometer sharedAccelerometer];
    
    accellerator.delegate = nil;
}

#pragma mark - Accelerometer

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
    UIAccelerationValue threshold = 2.0;
    if ((fabsf(acceleration.x) > threshold) || (fabsf(acceleration.y) > threshold) || (fabsf(acceleration.z) > threshold)) {
        if (!isShuffeling)
            [self shuffle];
    }
}

#pragma mark - Panel

- (void)buildPanel
{
    for (int i = 0; i < [game.tiles length]; i++) {
        UWTile *t = [[UWTile alloc] initWithView:panel scrollView:gameBoard withChar:[NSString stringWithFormat:@"%C", [game.tiles characterAtIndex:i]]];
        
        [panel addSubview:t];
        [tiles addObject:t];
        t.panelPos = i;
        t.center = CGPointMake(i * 318/7 + 2 + TILE_SIZE/2, panel.bounds.size.height/2 + 3);
    }
}

#pragma mark - Repaint

- (void)repaintAnimate
{
    [gameBoard setNeedsDisplay];
    if (step-- < 0) {
        [self.timer invalidate];
        
        // TODO: set bricks to played when all played tiles passed
        // TODO: remove tiles that was played and add new ones
    }
}

- (void)repaintWithAnimation
{
    step = 20;
    if (![self.timer isValid]) {
        timer = [[NSTimer timerWithTimeInterval:0.005 target:self selector:@selector(repaintAnimate) userInfo:nil repeats:YES] retain];
    }
    
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

#pragma mark - Presence channel events

- (void)presenceChannel:(PTPusherPresenceChannel *)channel didSubscribeWithMemberList:(NSArray *)members
{
    for (NSString *user in [members valueForKey:@"user_id"]) {
        if ([user isEqualToString:game.opponent]) {
            [online_indicator setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"online"]]];
        }
    } 
    [memberIDs addObjectsFromArray:[members valueForKey:@"user_id"]];
}

- (void)presenceChannel:(PTPusherPresenceChannel *)channel memberAdded:(NSDictionary *)memberData
{
    if ([(NSString *)[memberData objectForKey:@"user_id"] isEqualToString:game.opponent]) {
        [online_indicator setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"online"]]];
        [online_indicator setNeedsDisplay];
    }
    
    [memberIDs insertObject:[memberData objectForKey:@"user_id"] atIndex:0];
}

- (void)presenceChannel:(PTPusherPresenceChannel *)channel memberRemoved:(NSDictionary *)memberData
{
    if ([(NSString *)[memberData objectForKey:@"user_id"] isEqualToString:game.opponent]) {
        [online_indicator setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"offline"]]];
        [online_indicator setNeedsDisplay];
    }
    
    NSString *memberID = [memberData objectForKey:@"user_id"];
   // NSInteger indexOfMember = [memberIDs indexOfObject:memberID];
    
    [memberIDs removeObject:memberID];
}

#pragma mark - Subscribing

- (void)subscribeToPresenceChannel
{
    self.currentChannel = [self.pusher subscribeToPresenceChannelNamed:[NSString stringWithFormat:@"gid-%i", game.gameid] delegate:self];
}

- (void)dealloc {
    [board_view release];
    [gameBoard release];
    [panel release];
    [historyTableContainer release];
    [historyTableContainer release];
    [curtain release];
    [super dealloc];
}
@end
